from typing import List, Dict, Tuple
from sqlalchemy.orm import Session
from app.models.models import Student, StudentInterest, Preference
from app.config import settings

class RoommateMatchingService:
    def __init__(self, db: Session):
        self.db = db

    def calculate_habit_score(self, student1: Student, student2: Student) -> float:
        """计算作息习惯匹配分数"""
        sleeping_score = 1.0 if student1.sleeping_habit == student2.sleeping_habit else 0.5
        cleanliness_score = 1.0 if student1.cleanliness == student2.cleanliness else 0.5
        return (sleeping_score + cleanliness_score) / 2

    def calculate_interest_score(self, student1: Student, student2: Student) -> float:
        """计算兴趣爱好匹配分数"""
        student1_interests = {si.interest_id: si.interest_level for si in student1.interests}
        student2_interests = {si.interest_id: si.interest_level for si in student2.interests}
        
        common_interests = set(student1_interests.keys()) & set(student2_interests.keys())
        if not common_interests:
            return 0.0
        
        score = 0.0
        for interest_id in common_interests:
            level_diff = abs(student1_interests[interest_id] - student2_interests[interest_id])
            score += 1.0 - (level_diff / 4.0)  # 转换为0-1分
        
        return score / max(len(common_interests), 1)

    def calculate_preference_score(self, student1: Student, student2: Student) -> float:
        """计算互选偏好分数"""
        pref1 = self.db.query(Preference).filter(
            Preference.student_id == student1.id,
            Preference.preferred_student_id == student2.id
        ).first()
        
        pref2 = self.db.query(Preference).filter(
            Preference.student_id == student2.id,
            Preference.preferred_student_id == student1.id
        ).first()
        
        if not pref1 or not pref2:
            return 0.0
        
        return (pref1.preference_level + pref2.preference_level) / 10.0  # 转换为0-1分

    def calculate_matching_score(self, student1: Student, student2: Student) -> float:
        """计算总匹配分数"""
        if student1.gender != student2.gender:
            return 0.0
            
        habit_score = self.calculate_habit_score(student1, student2)
        interest_score = self.calculate_interest_score(student1, student2)
        preference_score = self.calculate_preference_score(student1, student2)
        
        total_score = (
            settings.HABIT_WEIGHT * habit_score +
            settings.INTEREST_WEIGHT * interest_score +
            settings.PREFERENCE_WEIGHT * preference_score
        )
        
        return total_score

    def get_recommended_roommates(self, student: Student, limit: int = 10) -> List[Tuple[Student, float]]:
        """获取推荐室友列表"""
        potential_roommates = (
            self.db.query(Student)
            .filter(Student.gender == student.gender)
            .filter(Student.id != student.id)
            .filter(Student.is_active == True)
            .all()
        )
        
        matches = []
        for roommate in potential_roommates:
            score = self.calculate_matching_score(student, roommate)
            if score > 0:
                matches.append((roommate, score))
        
        # 按分数降序排序
        matches.sort(key=lambda x: x[1], reverse=True)
        return matches[:limit]

    def get_matching_explanation(self, student1: Student, student2: Student) -> Dict:
        """获取匹配分数的详细解释"""
        habit_score = self.calculate_habit_score(student1, student2)
        interest_score = self.calculate_interest_score(student1, student2)
        preference_score = self.calculate_preference_score(student1, student2)
        total_score = self.calculate_matching_score(student1, student2)
        
        return {
            "total_score": total_score,
            "habit_score": habit_score,
            "interest_score": interest_score,
            "preference_score": preference_score,
            "explanation": {
                "habits": {
                    "sleeping": student1.sleeping_habit == student2.sleeping_habit,
                    "cleanliness": student1.cleanliness == student2.cleanliness
                },
                "common_interests": [
                    interest.interest.name
                    for interest in student1.interests
                    if any(i.interest_id == interest.interest_id for i in student2.interests)
                ],
                "mutual_preference": bool(
                    self.db.query(Preference)
                    .filter(
                        Preference.student_id == student1.id,
                        Preference.preferred_student_id == student2.id
                    ).first()
                    and
                    self.db.query(Preference)
                    .filter(
                        Preference.student_id == student2.id,
                        Preference.preferred_student_id == student1.id
                    ).first()
                )
            }
        } 